using System;
using System.Collections.Generic;

using Gdk;
using Gtk;
using Cairo;

namespace repragator
{
	[System.ComponentModel.ToolboxItem(true)]
	public partial class LayerView : Gtk.Bin
	{
		private Pixmap buffer;
		private double scale = 2, offsetX = 0, offsetY = 0;
		private bool forceRedraw = true;
		private List<Layer> currentRender;	 
		private double originX = 0, originY = 0;
		
		public LayerView ()
		{
			this.Build ();
			
			//this.drawingArea.MotionNotifyEvent += new MotionNotifyEventHandler(this.MotionNotify);
			
			//this.drawingArea.ButtonPressEvent += new ButtonPressEventHandler(this.ButtonPress);
			
			//this.drawingArea.ButtonReleaseEvent += new ButtonReleaseEventHandler(this.ButtonRelease);
			
			this.drawingArea.Events = EventMask.LeaveNotifyMask | EventMask.ButtonPressMask | EventMask.PointerMotionMask | EventMask.PointerMotionHintMask | EventMask.ButtonReleaseMask;
		}
		
		protected void MotionNotify(object sneder, MotionNotifyEventArgs e)
		{
			int x = 0, y = 0;
			ModifierType state = ModifierType.None;
			EventMotion ev = e.Event;
			
			if (!ev.IsHint)
			{
				x = (int)ev.X;
			
				y = (int)ev.Y;
			
				state = (ModifierType)ev.State;
			}
			
			if ((state & ModifierType.Button1Mask) != 0)
			{
				this.offsetX = this.originX*this.scale - ev.X*this.scale;
			
				this.offsetY = this.originY*this.scale - ev.Y*this.scale;
				
				this.forceRedraw = true;
				
				this.Draw();
			}
			
			e.RetVal = true;
		}
		
		protected void ButtonPress(object sender, ButtonPressEventArgs e)
		{
			EventButton ev = e.Event;
			
			if (ev.Button == 1)
			{
				this.originX = ev.X;
				
				this.originY = ev.Y;
			}
			
			e.RetVal = true;
		}
		
		protected void ButtonRelease(object sender, ButtonReleaseEventArgs e)
		{
			EventButton ev = e.Event;
			
			this.offsetX = this.originX*this.scale - ev.X*this.scale;
			
			this.offsetY = this.originY*this.scale - ev.Y*this.scale;
			
			this.forceRedraw = true;
			
			this.Draw();
			
			this.originX = 0;
			
			this.originY = 0;
			
			e.RetVal = true;	
		}
		
		public void Render(List<Layer> gcode)
		{
			this.currentRender = gcode;
			
			this.forceRedraw = true;
			
			this.Draw();
		}
		
		protected void Draw()
		{
			Gdk.GC gc = new Gdk.GC(this.drawingArea.GdkWindow);
			
			if (this.forceRedraw)
			{
				int stepScaled = Convert.ToInt32(10 * this.scale);
				
				this.buffer = new Pixmap(null, 401, 401, 24);
				
				gc.RgbFgColor = new Gdk.Color(0xe0, 0xff, 0xff);
				
				this.drawingArea.GdkWindow.Clear();
				
				this.buffer.DrawRectangle(gc, true, new Gdk.Rectangle(0, 0, 401, 401));
				
				gc.RgbFgColor = new Gdk.Color(0x00, 0x00, 0x00);
				
				for (int r = 0; r < 401; r += stepScaled)
				{
					this.buffer.DrawLine(gc, 0, r, 401, r);	
				}
				
				for (int co = 0; co < 401; co += stepScaled)
				{
					this.buffer.DrawLine(gc, co, 0, co, 401);
				}
				
				if (this.currentRender != null)
				{
					Move last = new Move(0, 0, false);
					int offsetXScaled = Convert.ToInt32(this.offsetX);
					int offsetYScaled = Convert.ToInt32(this.offsetY);
					
					foreach (Move current in this.currentRender[0].Moves)
					{
						if (!current.Extruded)
							gc.RgbFgColor = new Gdk.Color(0xff, 0x00, 0x00);
						
						this.buffer.DrawLine(gc, Convert.ToInt32(last.X*this.scale)-offsetXScaled, Convert.ToInt32(last.Y*this.scale)-offsetYScaled, Convert.ToInt32(current.X*this.scale)-offsetXScaled, Convert.ToInt32(current.Y*this.scale)-offsetYScaled);
						
						gc.RgbFgColor = new Gdk.Color(0x00, 0x00, 0x00);
						
						last = current;
					}
				}
				
				this.forceRedraw = false;
			}
			
			Context c = CairoHelper.Create(this.drawingArea.GdkWindow);
			
			CairoHelper.SetSourcePixmap(c, this.buffer, 0, 0);
			
			c.Paint();
			
			((IDisposable)c).Dispose();
		}

		protected void OnDrawingAreaExposeEvent (object o, ExposeEventArgs args)
		{
			this.Draw();
		}

		protected void OnDrawingAreaScrollEvent (object o, ScrollEventArgs args)
		{
			switch (args.Event.Direction)
			{
			case ScrollDirection.Up:
				this.scale += 0.2;
				break;
			case ScrollDirection.Down:
				this.scale -= 0.2;
				break;
			}
			
			this.forceRedraw = true;
		
			this.Draw();
		}
	}
}

